package com.kmxd.ams.core.common.query;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.ImmutableSet;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.common.constant.Constants;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.compress.utils.Lists;

/**
 * 根据条件自动生成相应对象
 *
 * @author ZuoLG
 */
@Slf4j
public class QueryGen {

  /**
   * 获取查询条件构造器QueryWrapper实例 通用查询条件已被封装完成
   *
   * @param searchObj 查询实体
   * @return QueryWrapper实例
   */
  public static <T> QueryWrapper<T> init(QueryWrapper<T> queryWrapper, Object searchObj) {
    try {
      // 区间条件组装 模糊查询 高级查询组装 简单排序 权限查询
      PropertyDescriptor[] origDescriptors = BeanUtil.getPropertyDescriptors(searchObj.getClass());
      String name, column;
      for (PropertyDescriptor property : origDescriptors) {
        name = property.getName();
        Object value = BeanUtil.getFieldValue(searchObj, name);
        column = getTableFieldName(searchObj.getClass(), name);

        if (column == null
            || judgedIsUselessField(name)
            || !PropertyUtils.isReadable(searchObj, name)
            || ObjectUtil.isNull(value)) {
          // column为null只有一种情况 那就是 添加了注解@TableField(exist = false) 后续都不用处理了
          continue;
        }

        //        log.error("打印对象的值:{},{},{}", name, column, value);
        if (value.equals(Constants.QUERY_NULL_DATA_PLACEHOLDER)
            || value.equals(NumberUtil.parseInt(Constants.QUERY_NULL_DATA_PLACEHOLDER))) {
          queryWrapper.isNull(StringUtils.camelToUnderline(column));
        } else if (Date.class.equals(property.getPropertyType())) {
          queryWrapper.eq(StringUtils.camelToUnderline(column), value);
        } else if (Integer.class.equals(property.getPropertyType())
            || Integer.TYPE.equals(property.getPropertyType())) {
          queryWrapper.eq(StringUtils.camelToUnderline(column), value);
        } else if (Long.class.equals(property.getPropertyType())
            || Long.TYPE.equals(property.getPropertyType())) {
          queryWrapper.eq(StringUtils.camelToUnderline(column), value);
        } else if (Boolean.class.equals(property.getPropertyType())
            || Boolean.TYPE.equals(property.getPropertyType())) {
          queryWrapper.eq(StringUtils.camelToUnderline(column), value);
        } else if (Float.class.equals(property.getPropertyType())
            || Float.TYPE.equals(property.getPropertyType())) {
          queryWrapper.eq(StringUtils.camelToUnderline(column), value);
        } else if (Double.class.equals(property.getPropertyType())
            || Double.TYPE.equals(property.getPropertyType())) {
          queryWrapper.eq(StringUtils.camelToUnderline(column), value);
        } else if (String.class.equals(property.getPropertyType())) {
          // 如果是tableId使用等于
          if (column.equalsIgnoreCase(Constants.TABLE_ID)) {
            if (StrUtil.isNotBlank(String.valueOf(value))) {
              queryWrapper.eq(StringUtils.camelToUnderline(column), String.valueOf(value).trim());
            }
          } else if (ImmutableSet.of("volIds", "docIds", "projIds", "boxIds").contains(column)) {
            // ids 查询统一到业务里面设置查询，不在此处处理
          } else if (ImmutableSet.of(
                      ArchConst.CLASSFY, StringUtils.underlineToCamel(ArchConst.CLASSFY_NAME))
                  .contains(column)
              && StrUtil.isNotBlank(String.valueOf(value))) {
            // 分类号，分类名称equals去匹配查询
            queryWrapper.eq(StringUtils.camelToUnderline(column), String.valueOf(value).trim());
          } else {
            if (StrUtil.isNotBlank(Optional.ofNullable(value).orElse("").toString())) {
              queryWrapper.like(StringUtils.camelToUnderline(column), String.valueOf(value).trim());
            }
          }
        }
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    return queryWrapper;
  }

  /**
   * 获取表字段名
   *
   * @param clazz
   * @param name
   * @return
   */
  private static String getTableFieldName(Class<?> clazz, String name) {
    try {
      // 如果字段加注解了@TableField(exist = false),不走DB查询
      Field field = null;
      try {
        field = clazz.getDeclaredField(name);
      } catch (Exception e) {
        // 不用处理此异常
        //        log.debug(e.getMessage());
      }
      // 如果为空，则去父类查找字段
      if (ObjectUtil.isNull(field)) {
        List<Field> allFields = getClassFields(clazz);
        List<Field> searchFields =
            allFields.stream().filter(a -> a.getName().equals(name)).collect(Collectors.toList());
        if (searchFields.size() > 0) {
          field = searchFields.get(0);
        }
      }
      if (ObjectUtil.isNotNull(field)) {
        assert field != null;
        TableField tableField = field.getAnnotation(TableField.class);
        if (tableField != null) {
          if (!tableField.exist()) {
            // 如果设置了TableField false 这个字段不需要处理
            return null;
          } else {
            String column = tableField.value();
            // 如果设置了TableField value 这个字段是实体字段
            if (StrUtil.isNotBlank(column)) {
              return column;
            }
          }
        }
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    return name;
  }

  /**
   * 获取class的 包括父类的
   *
   * @param clazz
   * @return
   */
  private static List<Field> getClassFields(Class<?> clazz) {
    List<Field> list = Lists.newArrayList();
    Field[] fields;
    do {
      fields = clazz.getDeclaredFields();
      list.addAll(Arrays.asList(fields));
      clazz = clazz.getSuperclass();
    } while (clazz != Object.class && clazz != null);
    return list;
  }

  /**
   * 排除这几个字段
   *
   * @param name
   * @return
   */
  private static boolean judgedIsUselessField(String name) {
    return "class".equals(name)
        || "ids".equals(name)
        || "page".equals(name)
        || "rows".equals(name)
        || "sort".equals(name)
        || "order".equals(name);
  }
}
